package su.msk.jet.team01.chatik.server.commands;

import su.msk.jet.team01.chatik.server.data.Client;
import su.msk.jet.team01.chatik.server.db.DatabaseAdapter;

import java.sql.SQLDataException;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class GetHistoryCommand extends Command {
	private static final String SQL_QUERY_SELECT_HISTORY_DATES = "SELECT DISTINCT date FROM history WHERE sender=? OR receiver=?";
	private static final String SQL_QUERY_SELECT_MESSAGES_HISTORY = "SELECT date, time, sender, receiver, message FROM history WHERE (sender=? OR receiver=?) AND date=?";
	private static DatabaseAdapter database = DatabaseAdapter.get();

	private static Logger logger = LoggerFactory.getLogger(GetHistoryCommand.class);
	
	public GetHistoryCommand() {
		super("history", 0);
	}

	@Override
	public void execute(final Client client, final String[] args) {
		String date = args[0];

		if (client.getName().isEmpty()) {
			client.send("You should select nick to view your private message history. Use /name command.");
			return;
		}

		if (date.isEmpty()) {
			client.send(translateHistoryDays(listHistoryDays(client.getName())));
		} else {
			client.send(translateHistoryDay(client.getName(), date));
		}
	}

	private List<String> getHistoryDay(final String clientName,
			final String date) throws ParseException, SQLException {
		String query = SQL_QUERY_SELECT_MESSAGES_HISTORY;
		List<Map<String, Object>> table;
		Map<String, Object> row;
		List<String> result = new ArrayList<String>();
		SimpleDateFormat dateFormatter = new SimpleDateFormat("dd-MM-yyyy");
		SimpleDateFormat timeFormatter = new SimpleDateFormat("HH:mm:ss");
		java.sql.Date dbDate;
		java.sql.Time dbTime;
		String fromName;
		String toName;
		String message;

		table = database.executeQuery(query, clientName, clientName,
				new java.sql.Date(dateFormatter.parse(date).getTime()));
		if (table != null) {
			for (int i = 0; i < table.size(); i++) {
				row = table.get(i);
				dbDate = (java.sql.Date) row.get("DATE");
				dbTime = (java.sql.Time) row.get("TIME");
				fromName = (String) row.get("SENDER");
				toName = (String) row.get("RECEIVER");
				message = (String) row.get("MESSAGE");
				result.add(String.format("[%s %s] %s (private) %s: %s",
						dateFormatter.format(dbDate),
						timeFormatter.format(dbTime), fromName, toName, message));
			}
		}
		return result;
	}

	private List<String> listHistoryDays(final String clientName) {
		String query = SQL_QUERY_SELECT_HISTORY_DATES;
		List<Map<String, Object>> table;
		Map<String, Object> row;
		List<String> result = new ArrayList<String>();
		SimpleDateFormat dateFormatter = new SimpleDateFormat("dd-MM-yyyy");
		java.sql.Date date;

		try {
			table = database.executeQuery(query, clientName, clientName);
			if (table != null) {
				for (int i = 0; i < table.size(); i++) {
					row = table.get(i);
					date = (java.sql.Date) row.get("DATE");
					result.add(String.format("%s", dateFormatter.format(date)));
				}
			}
		} catch(SQLException ex) {
			logger.error(ex.getMessage(), ex);
		}
		
		return result;
	}

	private String translateHistoryDay(final String name, final String date) {
		StringBuilder result = new StringBuilder();
		List<String> history;

		try {
			history = getHistoryDay(name, date);
		} catch(SQLDataException ex) {
			return "Invalid date specified";
		} catch(SQLException ex) {
			logger.error(ex.getMessage(), ex);
			return "Invalid date specified";
		} catch (ParseException ex) {
			return "Invalid date specified";
		}
		
		if (history.size() > 0) {
			for (String message : history) {
				result.append(message);
				result.append("\n");
			}
			result.delete(result.length() - 1, result.length());
		} else {
			result.append("No history found for that date");
		}

		return result.toString();
	}

	private String translateHistoryDays(final List<String> list) {
		StringBuilder result = new StringBuilder();

		if (list.size() > 0) {
			result.append("History days available: ");
			for (String key : list) {
				result.append(key).append(", ");
			}
			result.delete(result.length() - 2, result.length());
		} else {
			result.append("No history days available");
		}

		return result.toString();
	}
}
